import {useCallback, useRef, useState} from 'react';
import axios, {AxiosRequestConfig, CancelTokenSource} from 'axios';
import {useNavigate} from "react-router-dom";

interface ResponseData<T> {
    code: number;
    message: string;
    data: T;
}

export function useRequest<T>(options: AxiosRequestConfig) {
    const [data, setData] = useState<T | null>(null);
    const [error, setError] = useState<string | null | undefined>(null);
    const [loaded, setLoaded] = useState<boolean>(false);
    const cancelRef = useRef<CancelTokenSource | null>(null);
    const navigate = useNavigate()
    const request = useCallback(async (requestOptions: AxiosRequestConfig): Promise<T> => {
        setData(null);
        setError(null);
        setLoaded(false);
        const isLogin = localStorage.getItem('token')
        if (cancelRef.current) {
            cancelRef.current.cancel('Request canceled');
        }
        cancelRef.current = axios.CancelToken.source();

        try {
            const response = await axios.request<ResponseData<T>>({
                ...requestOptions,
                url: options?.url ? options.url : requestOptions.url,
                method: requestOptions?.method ? requestOptions.method : options.method,
                data: requestOptions?.data ? requestOptions.data : options.data,
                headers: {
                    'Authorization': isLogin
                },
                cancelToken: cancelRef.current.token
            });

            if (response.status === 403) {
                localStorage.removeItem('token');
                localStorage.removeItem('name');
                navigate('/login')
                throw new Error(response.data.message || 'Unauthorized access');
            }

            if (response.status !== 200) {
                throw new Error(response.data.message || 'Request failed');
            }

            if (response.data?.data === undefined) {
                throw new Error('Response data is undefined');
            }

            setData(response.data.data);
            return response.data.data;
        } catch (error) {
            if (axios.isCancel(error)) {
                console.warn('Request canceled:', error.message);
                return Promise.reject(error);
            }
            setError('Request error');
            throw error;
        } finally {
            setLoaded(true);
        }
    }, []);

    const cancel = useCallback(() => {
        if (cancelRef.current) {
            cancelRef.current.cancel('Request canceled manually');
        }
    }, []);

    return {data, error, loaded, request, cancel};
}
